package com.aloda.scoring.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.aloda.ai.AiPlatformTypeExecutor;
import com.aloda.ai.impl.ZhiPuAiPlatform;
import com.aloda.constant.AiConstant;
import com.aloda.constant.ErrorCode;
import com.aloda.constant.ExceptionConstant;
import com.aloda.context.UserBaseContext;
import com.aloda.dto.AiGenerateResultDTO;
import com.aloda.dto.AiMessageDTO;
import com.aloda.dto.QuestionAndResultListDTO;
import com.aloda.dto.question.AiQuestionTestDTO;
import com.aloda.dto.question.QuestionContentDTO;
import com.aloda.dto.scoringResult.AiScoreResult;
import com.aloda.dto.scoringResult.AiTestScoringDTO;
import com.aloda.entity.*;
import com.aloda.enums.AiPlatformEnum;
import com.aloda.exception.BaseException;
import com.aloda.mapper.UserTokenMapper;
import com.aloda.scoring.DataTreating;
import com.aloda.scoring.ScoringStrategy;
import com.aloda.scoring.anno.ScoringStrategyConfig;
import com.aloda.utils.MyJsonUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * AI测评类应用评分策略
 */
@Slf4j
@ScoringStrategyConfig(appType = 1, scoringStrategy = 1)
public class AiTestScoringStrategy implements ScoringStrategy {

    @Resource
    private DataTreating dataTreating;

    @Resource
    private UserTokenMapper userTokenMapper;

    @Resource
    private AiPlatformTypeExecutor aiPlatformTypeExecutor;

    @Resource
    private RedissonClient redissonClient;

    /**
     * 执行评分
     *
     * @param choices
     * @param app
     * @return
     * @throws Exception
     */
    @Override
    public UserAnswer doScore(List<String> choices, App app) throws Exception {
        Long userId = UserBaseContext.getUser().getId();
        String lockKey = "user:" + userId.toString() + ":answer-lock";
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁
            if (lock.tryLock(10, 60, TimeUnit.SECONDS)) {
                // 1.获取题目和评分结果列表
                QuestionAndResultListDTO questionAndResult = dataTreating.getQuestionAndResult(choices, app);
                Question question = questionAndResult.getQuestion();
                List<ScoringResult> scoringResultList = questionAndResult.getScoringResultList();

                // 2.取出用户所有题目与选项集合
                List<QuestionContentDTO> questionContentDTOS = JSONUtil.toList(question.getQuestionContent(), QuestionContentDTO.class);
                ArrayList<AiQuestionTestDTO> aiQuestionTestDTOS = new ArrayList<>();
                for (int i = 0; i < questionContentDTOS.size(); i++) {
                    AiQuestionTestDTO aiQuestionTestDTO = new AiQuestionTestDTO();
                    QuestionContentDTO questionContentDTO = questionContentDTOS.get(i);
                    aiQuestionTestDTO.setTitle(questionContentDTO.getTitle());
                    int flag = i;
                    List<QuestionContentDTO.Option> options = questionContentDTO.getOptions()
                            .stream()
                            .filter(option -> choices.get(flag).equals(option.getKey()))
                            .toList();
                    aiQuestionTestDTO.setValue(options.get(0).getValue());
                    aiQuestionTestDTO.setResult(options.get(0).getResult());
                    aiQuestionTestDTOS.add(aiQuestionTestDTO);
                }
                // 3.封装消息
                List<AiTestScoringDTO> aiTestScoringDTOS = BeanUtil.copyToList(scoringResultList, AiTestScoringDTO.class);
                String aiScoreScoringUserMessage = getAiTestScoringUserMessage(app,
                        aiQuestionTestDTOS,
                        aiTestScoringDTOS);
                // 4.1.查看用户tokens是否满足本次调用
                float needTokens = aiScoreScoringUserMessage.length() / AiConstant.TOKEN_CONVERSION_RATIO;
                LambdaQueryWrapper<UserToken> userTokenLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userTokenLambdaQueryWrapper.eq(UserToken::getUserId, userId);
                UserToken userToken = userTokenMapper.selectOne(userTokenLambdaQueryWrapper);
                if (userToken == null || userToken.getTokenNum() < needTokens) {
                    throw new BaseException(ExceptionConstant.USER_TOKEN_NOT_ENOUGH);
                }
                log.info("用户{}调用AI对评分类应用判题，预计token:{}",userId, needTokens);

                // 5.调用AI判题
                // 创建AI对话数据传输对象
                AiMessageDTO aiMessageDTO = new AiMessageDTO();
                aiMessageDTO.setSystemMessage(AiConstant.AI_TEST_SCORING_SYSTEM_MESSAGE);
                aiMessageDTO.setUserMessage(aiScoreScoringUserMessage);
                // 评分策略大模型固定使用智谱平台 GLM-4
                aiMessageDTO.setAiPlatform(AiPlatformEnum.ZHI_PU);
                aiMessageDTO.setModel(ZhiPuAiPlatform.ZhiPuModelEnum.ModelChatGLM4.getValue());
                aiMessageDTO.setTemperature(AiConstant.DEFAULT_TEMPERATURE);

                AiGenerateResultDTO aiGenerateResultDTO = null;
                try {
                    aiGenerateResultDTO = aiPlatformTypeExecutor.doSyncRequest(aiMessageDTO);
                } catch (Exception e) {
                    log.info("调用AI失败", e);
                    throw new BaseException(e.getMessage());
                }

                // 6.获取返回结果
                String aiGenerateResultDTOResult = aiGenerateResultDTO.getResult();
                log.info("用户{}调用AI对评分类应用判题结果：{}", userId, aiGenerateResultDTOResult);

                // 截取需要的 JSON 信息
                AiScoreResult aiScoreResult;
                try {
                    String jsonString = MyJsonUtils.cleanJsonString(aiGenerateResultDTOResult);
                    aiScoreResult = JSONUtil.toList(jsonString, AiScoreResult.class).get(0);
                } catch (Exception e) {
                    log.info("答案解析错误：", e);
                    throw new BaseException(ExceptionConstant.AI_GENERATE_ERROR);
                }
                // 7.封装UserAnswer
                // 查询id对应result
                if (aiScoreResult.getId() == null) {
                    throw new BaseException(ExceptionConstant.SCORING_ERROR);
                }
                List<ScoringResult> resultOneList = scoringResultList
                        .stream()
                        .filter(scoringResult -> scoringResult.getId().equals(aiScoreResult.getId()))
                        .toList();
                if (resultOneList.isEmpty()) {
                    throw new BaseException(ExceptionConstant.SCORING_ERROR);
                }

                // 8.扣除用户tokens
                userToken.setTokenNum(userToken.getTokenNum() - aiGenerateResultDTO.getTokenNum());
                if (userToken.getTokenNum() < 0) {
                    userToken.setTokenNum(0L);
                }
                userTokenMapper.updateById(userToken);

                // 9.封装返回数据
                UserAnswer userAnswer = new UserAnswer();
                userAnswer.setAppId(app.getId());
                userAnswer.setAppType(app.getAppType());
                userAnswer.setScoringStrategy(app.getScoringStrategy());
                userAnswer.setChoices(JSONUtil.toJsonStr(choices));
                userAnswer.setResultId(aiScoreResult.getId());
                userAnswer.setResultName(aiScoreResult.getResultName());
                userAnswer.setResultDesc(aiScoreResult.getResultDesc());
                userAnswer.setResultPicture(resultOneList.get(0).getResultPicture());
                userAnswer.setResultScore(0);
                return userAnswer;
            } else {
                throw new BaseException(ExceptionConstant.SYSTEM_BUSY);
            }
        }catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BaseException(ErrorCode.SYSTEM_ERROR);
        } finally {
            if (lock != null && lock.isLocked()) {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }

    }

    /**
     * 获取测评类AI判题用户消息
     * @param app 应用
     * @param questionTestDTOList 题目集合
     * @param scoringDTOList 评分结果集合
     * @return 用户消息
     */
    private String getAiTestScoringUserMessage(App app, List<AiQuestionTestDTO> questionTestDTOList, List<AiTestScoringDTO> scoringDTOList) {
        StringBuilder userMessage = new StringBuilder();
        userMessage.append(app.getAppName()).append("\n");
        userMessage.append(app.getAppDesc()).append("\n");
        userMessage.append(JSONUtil.toJsonStr(questionTestDTOList)).append("\n");
        userMessage.append(JSONUtil.toJsonStr(scoringDTOList));
        return userMessage.toString();
    }
}
